﻿// -----------------------------------------------------------------------
// <copyright file="GeneradorDeSelect.cs" company="Hexacta S.A.">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace generador
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    using gudusoft.gsqlparser;
    using System.Collections;
    using SQLVis.Entidades;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public static class GeneradorDeSelect
    {
       //limitaciones hasta el momento: join 1 tabla, no uso funciones como SELECT sum(field1) FROM, 
        //ORDER By no tiene, las expresiones solo con AND y no chequeo tipos de las columnas solo aplico valores enteros.., Ademas es limitada la cantidad
        public static InfoDeLaQuery GenerarSelect(DataSet ds, Dictionary<string, int> diccionario_Tabla_Cantidad_de_Registros)
        {
            TSelectSqlStatement statement = new TSelectSqlStatement(TDbVendor.DbVMssql);

            InfoDeLaQuery info = new InfoDeLaQuery();
            info.Query = statement;

            statement.IsParsed = true;
            TLzField column = null;
            TLzJoin join = null;

            DataTable tabla_elegida = Utiles.ElegirTablaAlAzar(ds);
            
            //LIMITACION JOIN CON 1 SOLA TABLA A LO SUMO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            IList<DataColumn> columnas_posibles;
            if (!TieneJoin(ds))
            {
                columnas_posibles = Utiles.ConvertirAIListFromDataColumnCollection(tabla_elegida.Columns);
                //Console.WriteLine("sin join");
                //Utiles.ImprimirIListDeDatacolumn(columnas_posibles);

                //info.RowsExamined=tabla_elegida.Rows.Count;  ROWS NO ME DA NADA PORQUE NO ESTOY CONECTADO
                info.RowsExamined = diccionario_Tabla_Cantidad_de_Registros[tabla_elegida.TableName];
             }
            else
            {
               // Console.WriteLine("con join");
                DataTable tabla_elegida2 = Utiles.ElegirTablaAlAzarDistintaDe(ds, tabla_elegida);

                columnas_posibles = Utiles.ConvertirAIListFromDataColumnCollection(tabla_elegida.Columns);
                foreach (DataColumn item in tabla_elegida2.Columns) //concateno las columnas de la 2da tabla
                {
                    columnas_posibles.Add(item);
                }
                join = new TLzJoin(statement);
                join.JoinTable = new TLzTable(statement);
                join.JoinTable.TableName = tabla_elegida2.TableName;
                statement.JoinTables.Add(join);

                //info.RowsExamined=tabla_elegida.Rows.Count + tabla_elegida2.Rows.Count; ROWS NO ME DA NADA PORQUE NO ESTOY CONECTADO
                info.RowsExamined = diccionario_Tabla_Cantidad_de_Registros[tabla_elegida.TableName] +
                                    diccionario_Tabla_Cantidad_de_Registros[tabla_elegida2.TableName];
            }
           
            IList<DataColumn> campos_elegidos=ElegirCamposDelSelect(statement, columnas_posibles);

            join = new TLzJoin(statement);
            join.JoinTable = new TLzTable(statement);
            join.JoinTable.TableName = tabla_elegida.TableName;
            statement.JoinTables.Add(join);


            if(Utiles.RandomEntreTrueYFalse())
            {
                AgregarWhere(statement, columnas_posibles);

                //SI TIENE WHERE NO SE BIEN CUANTOS REGISTRO RETORNARA, ENTONCES RANDOM DE LOS QUE EXAMINA
                info.RowsSent= Utiles.random.Next(info.RowsExamined); 
            }
            else
            {
                info.RowsSent= info.RowsExamined; 
            }


            if (Utiles.RandomEntreTrueYFalse())
            {
                int rdn= Utiles.random.Next(1,4);
 
                statement.GroupbyClause = new TLzGroupBy(statement);
                statement.GroupbyClause.GroupItems = new TLz_List(statement);
                AgregarGropuBy(statement, campos_elegidos, rdn); 
                
            }
           
            //DEMAS GILADAS VER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            //AGREGAR UN ORDER BY
            //DEMAS GILADAS VER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            info.LockTime = 0;

            return info;
        }

        private static void AgregarGropuBy(TSelectSqlStatement statement, IList<DataColumn> campos_elegidos, int p)
        {
            if (!(p == 0 || campos_elegidos.Count == 0))
            {
                TLzGroupByItem gi1 = new TLzGroupByItem(statement);
                gi1._ndExpr = new TLzCustomExpression(statement);
                var col = Utiles.ElegirElementoAlAzar<DataColumn>(campos_elegidos);
                gi1._ndExpr.AsText = col.ColumnName;
                statement.GroupbyClause.GroupItems.Add(gi1);

                campos_elegidos.Remove(col);
                p=p-1;
                AgregarGropuBy(statement, campos_elegidos, p);
            }
        }


        private static void AgregarWhere(TSelectSqlStatement statement, IList<DataColumn> columnas_posibles)
        {
            TLzCustomExpression where=new TLzCustomExpression(statement);

            int cantidad_binarias = DameAlAzarCantidadExpresionesBinarias();
            where= Utiles.GenerarExpresionWhereRecursivamente(columnas_posibles, where, cantidad_binarias);

            statement.WhereClauseText = where.AsText;
        }

        private static int DameAlAzarCantidadExpresionesBinarias()
        {
            
            return Utiles.random.Next(4);
        }

        private static bool TieneJoin(DataSet ds)
        {
            if (ds.Tables.Count < 2)
                return false;
            else
                return Utiles.RandomEntreTrueYFalse();
        }


        private static IList<DataColumn> ElegirCamposDelSelect(TSelectSqlStatement statement, IList<DataColumn> columnas)
        {
            TLzField column;
            IList<DataColumn> campos_elegidos = new List<DataColumn>();

            int cantidad_de_campos = Utiles.random.Next(Constantes.CantidadMaximaDeCampos);
            
            //si no especifico campos entonces seran todos los campos
            if (cantidad_de_campos == 0)
            {
                column = new TLzField(statement);
                column.FieldName = "*";
                statement.Fields.Add(column);

                campos_elegidos = columnas;
            }
            else
            {
                IList<DataColumn> posibles_campos = new List<DataColumn>();
                foreach (DataColumn columna in columnas)
                {
                    posibles_campos.Add(columna);
                }
                //elijo un campo posible, lo pongo en la query y luego lo saco de los posibles campos futuros a elegir
                int cantidad_de_campos_definitiva = Math.Min(cantidad_de_campos, posibles_campos.Count);//no pedir mas campos de los que tengo

                for (int i = 0; i < cantidad_de_campos_definitiva ; i++)
                {
                    DataColumn columna_elegida = Utiles.ElegirElementoAlAzar<DataColumn>(posibles_campos);

                    column = new TLzField(statement);
                    column.FieldName = columna_elegida.ColumnName;
                    statement.Fields.Add(column);

                    campos_elegidos.Add(columna_elegida);

                    posibles_campos.Remove(columna_elegida);
                }
            }

            return campos_elegidos;
        }
 
    }
}
